package com.xyzwps.paimon.furina.modules.auth.service

import com.auth0.jwt.JWT
import com.auth0.jwt.algorithms.Algorithm
import com.auth0.jwt.exceptions.JWTVerificationException
import com.xyzwps.paimon.furina.common.AppErrorCode
import com.xyzwps.paimon.furina.common.AppException
import com.xyzwps.paimon.furina.common.log
import com.xyzwps.paimon.furina.infra.AppProperties
import org.springframework.stereotype.Service
import java.time.Instant
import java.util.Base64
import java.util.UUID
import kotlin.time.Duration
import kotlin.time.toJavaDuration

@Service
class JwtService(config: AppProperties) {

    private val issuer: String = config.session.jwt.issuer.ifBlank { throw RuntimeException("No issuer") }
    private val expire: Duration = config.session.jwt.expire()
    private val algorithm: Algorithm = run {
        try {
            Algorithm.HMAC512(Base64.getDecoder().decode(config.session.jwt.hs512key))
        } catch (e: Exception) {
            throw RuntimeException("invalid HS512 key", e)
        }
    }


    fun createJwt(userId: Long): JwtCreateResult {
        val expiresAt = Instant.now().plus(expire.toJavaDuration())
        val jwt = JWT.create()
            .withJWTId(UUID.randomUUID().toString())
            .withSubject("$userId")
            .withIssuer(issuer)
            .withExpiresAt(expiresAt)
            .withIssuedAt(Instant.now())
            .sign(algorithm)
        return JwtCreateResult(jwt, expiresAt, expire)
    }

    fun verifyJwt(jwt: String): JwtVerifyResult {
        try {
            val verifier = JWT.require(algorithm)
                .withIssuer(issuer)
                .build();
            val decoded = verifier.verify(jwt)
            return JwtVerifyResult(userId = decoded.subject.toLong(), sessionId = decoded.id)
        } catch (e: JWTVerificationException) {
            log.error("token is invalid", e)
            throw AppException(AppErrorCode.TOKEN_INVALID, e.message ?: "Token is invalid.")
        }
    }
}



